Micron Document
πŸŽ–οΈGitΠ―Ρ€Π°πŸŽ–οΈ

Node / meshtastic / Meshtastic-Android / files / core / service / src / commonMain / kotlin / org / meshtastic / core / service / AdminControllerImpl.kt

Displaying Raw β€’ Download

core/service/src/commonMain/kotlin/org/meshtastic/core/service/AdminControllerImpl.kt 4d4070c8e1ed73a56ee2f054300a0f62e3fe2e62 (4d4070c8) Text, 20.57 KB

T8b949e/*
* Copyright (c) 2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tff7b72package T7ee787org.meshtastic.core.service

Tff7b72import T7ee787co.touchlab.kermit.Logger
Tff7b72import T7ee787kotlinx.atomicfu.locks.SynchronizedObject
Tff7b72import T7ee787kotlinx.atomicfu.locks.synchronized
Tff7b72import T7ee787kotlinx.coroutines.CoroutineScope
Tff7b72import T7ee787kotlinx.coroutines.NonCancellable
Tff7b72import T7ee787kotlinx.coroutines.flow.first
Tff7b72import T7ee787kotlinx.coroutines.flow.firstOrNull
Tff7b72import T7ee787kotlinx.coroutines.withContext
Tff7b72import T7ee787kotlinx.coroutines.withTimeoutOrNull
Tff7b72import T7ee787okio.ByteString
Tff7b72import T7ee787okio.ByteString.Companion.toByteString
Tff7b72import T7ee787org.meshtastic.core.common.util.handledLaunch
Tff7b72import T7ee787org.meshtastic.core.common.util.nowMillis
Tff7b72import T7ee787org.meshtastic.core.common.util.nowSeconds
Tff7b72import T7ee787org.meshtastic.core.model.Position
Tff7b72import T7ee787org.meshtastic.core.repository.AdminController
Tff7b72import T7ee787org.meshtastic.core.repository.AdminEditScope
Tff7b72import T7ee787org.meshtastic.core.repository.AwaitedSendStatus
Tff7b72import T7ee787org.meshtastic.core.repository.CommandSender
Tff7b72import T7ee787org.meshtastic.core.repository.ConnectionStateProvider
Tff7b72import T7ee787org.meshtastic.core.repository.EditSettingsTransactionException
Tff7b72import T7ee787org.meshtastic.core.repository.LocalNodeUnavailableException
Tff7b72import T7ee787org.meshtastic.core.repository.NodeManager
Tff7b72import T7ee787org.meshtastic.core.repository.RadioConfigRepository
Tff7b72import T7ee787org.meshtastic.core.repository.toFixedPositionAdminMessage
Tff7b72import T7ee787org.meshtastic.core.repository.toFixedPositionProto
Tff7b72import T7ee787org.meshtastic.proto.AdminMessage
Tff7b72import T7ee787org.meshtastic.proto.Channel
Tff7b72import T7ee787org.meshtastic.proto.Config
Tff7b72import T7ee787org.meshtastic.proto.HamParameters
Tff7b72import T7ee787org.meshtastic.proto.ModuleConfig
Tff7b72import T7ee787org.meshtastic.proto.OTAMode
Tff7b72import T7ee787org.meshtastic.proto.User
Tff7b72import T7ee787kotlin.time.Duration.Companion.seconds

T8b949e/**
* Additional window for observing local transport departure after a dispatched commit loses its response. The
* surrounding NonCancellable finalization can take longer because [CommandSender.sendAdminAwaitResult] first waits
* behind older FIFO entries and then owns its radio-response window.
*/
Tff7b72internal Tff7b72val Te6edf3COMMIT_DEPARTURE_TIMEOUT Tff7b72= T79c0ff5.Te6edf3seconds

Tff7b72internal Tff7b72fun Td2a8ffeditSettingsBoundaryFailureMessageTb4b4b4(Te6edf3boundaryTb4b4b4: Tffa657StringTb4b4b4)Tb4b4b4: Tffa657String Tff7b72=
Ta5d6ff"Ta5d6ffDevice rejected or timed out while sending edit-settings Tffd700$Te6edf3boundaryTa5d6ff"

Tff7b72internal Tff7b72fun Td2a8ffeditSettingsCommitFailureMessageTb4b4b4(Te6edf3statusTb4b4b4: Te6edf3AwaitedSendStatusTb4b4b4, Te6edf3dispatchedTb4b4b4: Tffa657BooleanTb4b4b4)Tb4b4b4: Tffa657String Tff7b72=
Ta5d6ff"Ta5d6ffDevice rejected or timed out while sending edit-settings commit (status=Tffd700$Te6edf3statusTa5d6ff, dispatched=Tffd700$Te6edf3dispatchedTa5d6ff)Ta5d6ff"

T8b949e/**
* [AdminController] implementation: local/remote configuration, channels, owner, device lifecycle, and the
* [editSettings] transaction.
*
* Focused collaborator of [RadioControllerImpl]. Builds [AdminMessage] protos directly and delegates to [CommandSender]
* for transport, mirroring the SDK's `AdminApiImpl` pattern. Standalone writes may update local caches optimistically;
* transactional writes stage their local projections until commit acceptance so failed edits cannot publish settings
* the device did not commit. The device remains the source of truth and re-sends its full config on every connection.
*/
Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffTooManyFunctionsTa5d6ff"Tb4b4b4)
Tff7b72internal Tff7b72class T56d364AdminControllerImplTb4b4b4(
Tff7b72private Tff7b72val Te6edf3commandSenderTb4b4b4: Te6edf3CommandSenderTb4b4b4,
Tff7b72private Tff7b72val Te6edf3nodeManagerTb4b4b4: Te6edf3NodeManagerTb4b4b4,
Tff7b72private Tff7b72val Te6edf3radioConfigRepositoryTb4b4b4: Te6edf3RadioConfigRepositoryTb4b4b4,
Tff7b72private Tff7b72val Te6edf3connectionStateProviderTb4b4b4: Te6edf3ConnectionStateProviderTb4b4b4,
Tff7b72private Tff7b72val Te6edf3scopeTb4b4b4: Te6edf3CoroutineScopeTb4b4b4,
Tb4b4b4) Tb4b4b4: Te6edf3AdminController Tb4b4b4{

Tff7b72private Tff7b72val Te6edf3myNodeNumTb4b4b4: Tffa657Int
Tff7b72getTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3nodeManagerTb4b4b4.Te6edf3myNodeNumTb4b4b4.Te6edf3value Tff7b72?: T79c0ff0

T8b949e// ── Owner ───────────────────────────────────────────────────────────────

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffsetOwnerTb4b4b4(Te6edf3destNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3userTb4b4b4: Te6edf3UserTb4b4b4, Te6edf3packetIdTb4b4b4: Tffa657IntTb4b4b4) Tb4b4b4{
Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3packetIdTb4b4b4) Tb4b4b4{ Te6edf3AdminMessageTb4b4b4(Te6edf3set_owner Tff7b72= Te6edf3userTb4b4b4) Tb4b4b4}
Te6edf3nodeManagerTb4b4b4.Te6edf3handleReceivedUserTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3userTb4b4b4)
Tb4b4b4}

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffgetOwnerTb4b4b4(Te6edf3destNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3packetIdTb4b4b4: Tffa657IntTb4b4b4) Tb4b4b4{
Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3packetIdTb4b4b4, Te6edf3wantResponse Tff7b72= Tff7b72trueTb4b4b4) Tb4b4b4{ Te6edf3AdminMessageTb4b4b4(Te6edf3get_owner_request Tff7b72= Tff7b72trueTb4b4b4) Tb4b4b4}
Tb4b4b4}

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffsetHamModeTb4b4b4(Te6edf3destNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3hamParametersTb4b4b4: Te6edf3HamParametersTb4b4b4, Te6edf3packetIdTb4b4b4: Tffa657IntTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3destNum Tff7b72!Tff7b72= Te6edf3nodeManagerTb4b4b4.Te6edf3myNodeNumTb4b4b4.Te6edf3valueTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3w Tb4b4b4{ Ta5d6ff"Ta5d6ffIgnoring setHamMode for node Tffd700$Te6edf3destNumTa5d6ff β€” ham onboarding targets the local node onlyTa5d6ff" Tb4b4b4}
Tff7b72return
Tb4b4b4}
T8b949e// Firmware applies tx_power/frequency to the LoRa config verbatim, so echo the node's current
T8b949e// values to keep a re-send (e.g. a callsign edit while already licensed) from wiping overrides.
Tff7b72val Te6edf3lora Tff7b72= Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3localConfigFlowTb4b4b4.Te6edf3firstOrNullTb4b4b4(Tb4b4b4)Tff7b72?.Te6edf3lora Tff7b72?: Te6edf3ConfigTb4b4b4.Te6edf3LoRaConfigTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3params Tff7b72= Te6edf3hamParametersTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3tx_power Tff7b72= Te6edf3loraTb4b4b4.Te6edf3tx_powerTb4b4b4, Te6edf3frequency Tff7b72= Te6edf3loraTb4b4b4.Te6edf3override_frequencyTb4b4b4)
Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3packetIdTb4b4b4) Tb4b4b4{ Te6edf3AdminMessageTb4b4b4(Te6edf3set_ham_mode Tff7b72= Te6edf3paramsTb4b4b4) Tb4b4b4}
Tff7b72val Te6edf3currentUser Tff7b72= Te6edf3nodeManagerTb4b4b4.Te6edf3nodeDBbyNodeNumTff7b72[Te6edf3destNumTff7b72]Tff7b72?.Te6edf3user Tff7b72?: Te6edf3UserTb4b4b4(Tb4b4b4)
Te6edf3nodeManagerTb4b4b4.Te6edf3handleReceivedUserTb4b4b4(
Te6edf3destNumTb4b4b4,
Te6edf3currentUserTb4b4b4.Te6edf3copyTb4b4b4(
Te6edf3long_name Tff7b72= Te6edf3hamParametersTb4b4b4.Te6edf3call_signTb4b4b4,
Te6edf3short_name Tff7b72= Te6edf3hamParametersTb4b4b4.Te6edf3short_nameTb4b4b4,
Te6edf3is_licensed Tff7b72= Tff7b72trueTb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4}

T8b949e// ── Configuration ─────────────────────────────────────────────────────────

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffsetLocalConfigTb4b4b4(Te6edf3configTb4b4b4: Te6edf3ConfigTb4b4b4) Tb4b4b4{
Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminTb4b4b4(Te6edf3myNodeNumTb4b4b4) Tb4b4b4{ Te6edf3AdminMessageTb4b4b4(Te6edf3set_config Tff7b72= Te6edf3configTb4b4b4) Tb4b4b4}
Te6edf3scopeTb4b4b4.Te6edf3handledLaunch Tb4b4b4{ Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3setLocalConfigTb4b4b4(Te6edf3configTb4b4b4) Tb4b4b4}
Tb4b4b4}

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffsetConfigTb4b4b4(Te6edf3destNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3configTb4b4b4: Te6edf3ConfigTb4b4b4, Te6edf3packetIdTb4b4b4: Tffa657IntTb4b4b4) Tb4b4b4{
Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3packetIdTb4b4b4) Tb4b4b4{ Te6edf3AdminMessageTb4b4b4(Te6edf3set_config Tff7b72= Te6edf3configTb4b4b4) Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3destNum Tff7b72=Tff7b72= Te6edf3nodeManagerTb4b4b4.Te6edf3myNodeNumTb4b4b4.Te6edf3valueTb4b4b4) Tb4b4b4{
Te6edf3scopeTb4b4b4.Te6edf3handledLaunch Tb4b4b4{ Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3setLocalConfigTb4b4b4(Te6edf3configTb4b4b4) Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffgetConfigTb4b4b4(Te6edf3destNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3configTypeTb4b4b4: Tffa657IntTb4b4b4, Te6edf3packetIdTb4b4b4: Tffa657IntTb4b4b4) Tb4b4b4{
Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3packetIdTb4b4b4, Te6edf3wantResponse Tff7b72= Tff7b72trueTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3configType Tff7b72=Tff7b72= Te6edf3AdminMessageTb4b4b4.Te6edf3ConfigTypeTb4b4b4.Te6edf3SESSIONKEY_CONFIGTb4b4b4.Te6edf3valueTb4b4b4) Tb4b4b4{
Te6edf3AdminMessageTb4b4b4(Te6edf3get_device_metadata_request Tff7b72= Tff7b72trueTb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3AdminMessageTb4b4b4(Te6edf3get_config_request Tff7b72= Te6edf3AdminMessageTb4b4b4.Te6edf3ConfigTypeTb4b4b4.Te6edf3fromValueTb4b4b4(Te6edf3configTypeTb4b4b4)Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffsetModuleConfigTb4b4b4(Te6edf3destNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3configTb4b4b4: Te6edf3ModuleConfigTb4b4b4, Te6edf3packetIdTb4b4b4: Tffa657IntTb4b4b4) Tb4b4b4{
Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3packetIdTb4b4b4) Tb4b4b4{ Te6edf3AdminMessageTb4b4b4(Te6edf3set_module_config Tff7b72= Te6edf3configTb4b4b4) Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3destNum Tff7b72=Tff7b72= Te6edf3nodeManagerTb4b4b4.Te6edf3myNodeNumTb4b4b4.Te6edf3valueTb4b4b4) Tb4b4b4{
Te6edf3configTb4b4b4.Te6edf3statusmessageTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3sm Tff7b72-Tff7b72> Te6edf3nodeManagerTb4b4b4.Te6edf3updateNodeStatusTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3smTb4b4b4.Te6edf3node_statusTb4b4b4) Tb4b4b4}
Te6edf3scopeTb4b4b4.Te6edf3handledLaunch Tb4b4b4{ Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3setLocalModuleConfigTb4b4b4(Te6edf3configTb4b4b4) Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffgetModuleConfigTb4b4b4(Te6edf3destNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3moduleConfigTypeTb4b4b4: Tffa657IntTb4b4b4, Te6edf3packetIdTb4b4b4: Tffa657IntTb4b4b4) Tb4b4b4{
Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3packetIdTb4b4b4, Te6edf3wantResponse Tff7b72= Tff7b72trueTb4b4b4) Tb4b4b4{
Te6edf3AdminMessageTb4b4b4(Te6edf3get_module_config_request Tff7b72= Te6edf3AdminMessageTb4b4b4.Te6edf3ModuleConfigTypeTb4b4b4.Te6edf3fromValueTb4b4b4(Te6edf3moduleConfigTypeTb4b4b4)Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

T8b949e// ── Channels ────────────────────────────────────────────────────────────

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffsetLocalChannelTb4b4b4(Te6edf3channelTb4b4b4: Te6edf3ChannelTb4b4b4) Tb4b4b4{
Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminTb4b4b4(Te6edf3myNodeNumTb4b4b4) Tb4b4b4{ Te6edf3AdminMessageTb4b4b4(Te6edf3set_channel Tff7b72= Te6edf3channelTb4b4b4) Tb4b4b4}
Te6edf3scopeTb4b4b4.Te6edf3handledLaunch Tb4b4b4{ Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3updateChannelSettingsTb4b4b4(Te6edf3channelTb4b4b4) Tb4b4b4}
Tb4b4b4}

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffsetRemoteChannelTb4b4b4(Te6edf3destNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3channelTb4b4b4: Te6edf3ChannelTb4b4b4, Te6edf3packetIdTb4b4b4: Tffa657IntTb4b4b4) Tb4b4b4{
Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3packetIdTb4b4b4) Tb4b4b4{ Te6edf3AdminMessageTb4b4b4(Te6edf3set_channel Tff7b72= Te6edf3channelTb4b4b4) Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3destNum Tff7b72=Tff7b72= Te6edf3nodeManagerTb4b4b4.Te6edf3myNodeNumTb4b4b4.Te6edf3valueTb4b4b4) Tb4b4b4{
Te6edf3scopeTb4b4b4.Te6edf3handledLaunch Tb4b4b4{ Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3updateChannelSettingsTb4b4b4(Te6edf3channelTb4b4b4) Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffgetChannelTb4b4b4(Te6edf3destNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3indexTb4b4b4: Tffa657IntTb4b4b4, Te6edf3packetIdTb4b4b4: Tffa657IntTb4b4b4) Tb4b4b4{
Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3packetIdTb4b4b4, Te6edf3wantResponse Tff7b72= Tff7b72trueTb4b4b4) Tb4b4b4{
Te6edf3AdminMessageTb4b4b4(Te6edf3get_channel_request Tff7b72= Te6edf3index Tff7b72+ T79c0ff1Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

T8b949e// ── Ringtone & Canned Messages ─────────────────────────────────────────

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffsetRingtoneTb4b4b4(Te6edf3destNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3ringtoneTb4b4b4: Tffa657StringTb4b4b4) Tb4b4b4{
Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminTb4b4b4(Te6edf3destNumTb4b4b4) Tb4b4b4{ Te6edf3AdminMessageTb4b4b4(Te6edf3set_ringtone_message Tff7b72= Te6edf3ringtoneTb4b4b4) Tb4b4b4}
Tb4b4b4}

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffgetRingtoneTb4b4b4(Te6edf3destNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3packetIdTb4b4b4: Tffa657IntTb4b4b4) Tb4b4b4{
Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3packetIdTb4b4b4, Te6edf3wantResponse Tff7b72= Tff7b72trueTb4b4b4) Tb4b4b4{ Te6edf3AdminMessageTb4b4b4(Te6edf3get_ringtone_request Tff7b72= Tff7b72trueTb4b4b4) Tb4b4b4}
Tb4b4b4}

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffsetCannedMessagesTb4b4b4(Te6edf3destNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3messagesTb4b4b4: Tffa657StringTb4b4b4) Tb4b4b4{
Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminTb4b4b4(Te6edf3destNumTb4b4b4) Tb4b4b4{ Te6edf3AdminMessageTb4b4b4(Te6edf3set_canned_message_module_messages Tff7b72= Te6edf3messagesTb4b4b4) Tb4b4b4}
Tb4b4b4}

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffsetTimeTb4b4b4(Te6edf3destNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3packetIdTb4b4b4: Tffa657IntTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3i Tb4b4b4{ Ta5d6ff"Ta5d6ffSet time requested for node Tffd700$Te6edf3destNumTa5d6ff" Tb4b4b4}
T8b949e// Resolve the timestamp at send time so the value is as fresh as possible when it leaves the phone.
Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3packetIdTb4b4b4) Tb4b4b4{ Te6edf3AdminMessageTb4b4b4(Te6edf3set_time_only Tff7b72= Te6edf3nowSecondsTb4b4b4.Te6edf3toIntTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffgetCannedMessagesTb4b4b4(Te6edf3destNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3packetIdTb4b4b4: Tffa657IntTb4b4b4) Tb4b4b4{
Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3packetIdTb4b4b4, Te6edf3wantResponse Tff7b72= Tff7b72trueTb4b4b4) Tb4b4b4{
Te6edf3AdminMessageTb4b4b4(Te6edf3get_canned_message_module_messages_request Tff7b72= Tff7b72trueTb4b4b4)
Tb4b4b4}
Tb4b4b4}

T8b949e// ── Position ────────────────────────────────────────────────────────────

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffsetFixedPositionTb4b4b4(Te6edf3destNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3positionTb4b4b4: Te6edf3PositionTb4b4b4) Tb4b4b4{
Te6edf3commandSenderTb4b4b4.Te6edf3setFixedPositionTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3positionTb4b4b4)
Tb4b4b4}

T8b949e// ── Device Status & Lifecycle ───────────────────────────────────────────

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffgetDeviceConnectionStatusTb4b4b4(Te6edf3destNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3packetIdTb4b4b4: Tffa657IntTb4b4b4) Tb4b4b4{
Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3packetIdTb4b4b4, Te6edf3wantResponse Tff7b72= Tff7b72trueTb4b4b4) Tb4b4b4{
Te6edf3AdminMessageTb4b4b4(Te6edf3get_device_connection_status_request Tff7b72= Tff7b72trueTb4b4b4)
Tb4b4b4}
Tb4b4b4}

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffrebootTb4b4b4(Te6edf3destNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3packetIdTb4b4b4: Tffa657IntTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3i Tb4b4b4{ Ta5d6ff"Ta5d6ffReboot requested for node Tffd700$Te6edf3destNumTa5d6ff" Tb4b4b4}
Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3packetIdTb4b4b4) Tb4b4b4{ Te6edf3AdminMessageTb4b4b4(Te6edf3reboot_seconds Tff7b72= Te6edf3DEFAULT_DELAY_SECONDSTb4b4b4) Tb4b4b4}
Tb4b4b4}

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffrebootToDfuTb4b4b4(Te6edf3nodeNumTb4b4b4: Tffa657IntTb4b4b4) Tb4b4b4{
Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminTb4b4b4(Te6edf3nodeNumTb4b4b4) Tb4b4b4{ Te6edf3AdminMessageTb4b4b4(Te6edf3enter_dfu_mode_request Tff7b72= Tff7b72trueTb4b4b4) Tb4b4b4}
Tb4b4b4}

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffrequestRebootOtaTb4b4b4(Te6edf3requestIdTb4b4b4: Tffa657IntTb4b4b4, Te6edf3destNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3modeTb4b4b4: Tffa657IntTb4b4b4, Te6edf3hashTb4b4b4: Te6edf3ByteArray?Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3otaMode Tff7b72= Te6edf3OTAModeTb4b4b4.Te6edf3fromValueTb4b4b4(Te6edf3modeTb4b4b4) Tff7b72?: Te6edf3OTAModeTb4b4b4.Te6edf3NO_REBOOT_OTA
Tff7b72val Te6edf3otaEvent Tff7b72=
Te6edf3AdminMessageTb4b4b4.Te6edf3OTAEventTb4b4b4(Te6edf3reboot_ota_mode Tff7b72= Te6edf3otaModeTb4b4b4, Te6edf3ota_hash Tff7b72= Te6edf3hashTff7b72?.Te6edf3toByteStringTb4b4b4(Tb4b4b4) Tff7b72?: Te6edf3ByteStringTb4b4b4.Te6edf3EMPTYTb4b4b4)
Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3requestIdTb4b4b4) Tb4b4b4{ Te6edf3AdminMessageTb4b4b4(Te6edf3ota_request Tff7b72= Te6edf3otaEventTb4b4b4) Tb4b4b4}
Tb4b4b4}

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffshutdownTb4b4b4(Te6edf3destNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3packetIdTb4b4b4: Tffa657IntTb4b4b4) Tb4b4b4{
Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3packetIdTb4b4b4) Tb4b4b4{ Te6edf3AdminMessageTb4b4b4(Te6edf3shutdown_seconds Tff7b72= Te6edf3DEFAULT_DELAY_SECONDSTb4b4b4) Tb4b4b4}
Tb4b4b4}

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8fffactoryResetTb4b4b4(Te6edf3destNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3packetIdTb4b4b4: Tffa657IntTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3i Tb4b4b4{ Ta5d6ff"Ta5d6ffFactory reset requested for node Tffd700$Te6edf3destNumTa5d6ff" Tb4b4b4}
Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3packetIdTb4b4b4) Tb4b4b4{ Te6edf3AdminMessageTb4b4b4(Te6edf3factory_reset_device Tff7b72= T79c0ff1Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffnodedbResetTb4b4b4(Te6edf3destNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3packetIdTb4b4b4: Tffa657IntTb4b4b4, Te6edf3preserveFavoritesTb4b4b4: Tffa657BooleanTb4b4b4) Tb4b4b4{
Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3packetIdTb4b4b4) Tb4b4b4{ Te6edf3AdminMessageTb4b4b4(Te6edf3nodedb_reset Tff7b72= Te6edf3preserveFavoritesTb4b4b4) Tb4b4b4}
Tb4b4b4}

T8b949e// ── Edit Settings (transactional) ───────────────────────────────────────

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffeditSettingsTb4b4b4(Te6edf3destNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3blockTb4b4b4: Te6edf3suspend Te6edf3AdminEditScopeTb4b4b4.Tb4b4b4(Tb4b4b4) Tff7b72-Tff7b72> Tffa657UnitTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3isLocalDestination Tff7b72= Te6edf3destNum Tff7b72=Tff7b72= Te6edf3nodeManagerTb4b4b4.Te6edf3myNodeNumTb4b4b4.Te6edf3value
Te6edf3requireBeginBoundaryAcceptedTb4b4b4(Te6edf3destNumTb4b4b4)

T8b949e// Firmware has no abort boundary. Preserve any block failure, including cancellation, only long enough to
T8b949e// attempt the commit that closes the accepted session; the original failure is restored below. Local cache
T8b949e// projections are staged by the session and become visible only after both the block and commit succeed.
Tff7b72val Te6edf3session Tff7b72= Te6edf3EditSettingsSessionTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3isLocalDestinationTb4b4b4)
Tff7b72val Te6edf3blockResult Tff7b72= Te6edf3runCatching Tb4b4b4{ Te6edf3sessionTb4b4b4.Te6edf3blockTb4b4b4(Tb4b4b4) Tb4b4b4}
Tff7b72val Te6edf3commitResult Tff7b72= Te6edf3runCatching Tb4b4b4{
Te6edf3withContextTb4b4b4(Te6edf3NonCancellableTb4b4b4) Tb4b4b4{ Te6edf3requireCommitBoundaryAcceptedTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3isLocalDestinationTb4b4b4) Tb4b4b4}
Tb4b4b4}

Te6edf3blockResultTb4b4b4.Te6edf3exceptionOrNullTb4b4b4(Tb4b4b4)Tff7b72?.Te6edf3let Tb4b4b4{ Te6edf3blockFailure Tff7b72-Tff7b72>
T8b949e// Coroutine stack-trace recovery may rebuild the same exception across the NonCancellable boundary.
Te6edf3commitResult
Tb4b4b4.Te6edf3exceptionOrNullTb4b4b4(Tb4b4b4)
Tff7b72?.Te6edf3takeUnless Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3containsCauseIdentityTb4b4b4(Te6edf3blockFailureTb4b4b4) Tb4b4b4}
Tff7b72?.Te6edf3letTb4b4b4(Te6edf3blockFailureTff7b72::Te6edf3addSuppressedTb4b4b4)
Tff7b72throw Te6edf3blockFailure
Tb4b4b4}
Te6edf3commitResultTb4b4b4.Te6edf3getOrThrowTb4b4b4(Tb4b4b4)
Te6edf3sessionTb4b4b4.Te6edf3applyStagedProjectionsTb4b4b4(Tb4b4b4)
Tb4b4b4}

Tff7b72private Tff7b72fun Te6edf3ThrowableTb4b4b4.Td2a8ffcontainsCauseIdentityTb4b4b4(Te6edf3expectedTb4b4b4: Te6edf3ThrowableTb4b4b4)Tb4b4b4: Tffa657Boolean Tb4b4b4{
Tff7b72val Te6edf3visited Tff7b72= Te6edf3mutableListOfTff7b72<Te6edf3ThrowableTff7b72>Tb4b4b4(Tb4b4b4)
Tff7b72var Te6edf3currentTb4b4b4: Te6edf3Throwable? Tff7b72= Tff7b72this
Tff7b72var Te6edf3found Tff7b72= Tff7b72false
Tff7b72while Tb4b4b4(Te6edf3current Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3candidate Tff7b72= Te6edf3current
Tff7b72if Tb4b4b4(Te6edf3visitedTb4b4b4.Te6edf3any Tb4b4b4{ Tffa657it Tff7b72=Tff7b72=Tff7b72= Te6edf3candidate Tb4b4b4}Tb4b4b4) Tb4b4b4{
Te6edf3current Tff7b72= Tff7b72null
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3found Tff7b72= Te6edf3candidate Tff7b72=Tff7b72=Tff7b72= Te6edf3expected
Te6edf3visited Tff7b72+Tff7b72= Te6edf3candidate
Te6edf3current Tff7b72= Te6edf3candidateTb4b4b4.Te6edf3causeTb4b4b4.Te6edf3takeUnless Tb4b4b4{ Te6edf3found Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72return Te6edf3found
Tb4b4b4}

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffeditLocalSettingsTb4b4b4(Te6edf3blockTb4b4b4: Te6edf3suspend Te6edf3AdminEditScopeTb4b4b4.Tb4b4b4(Tb4b4b4) Tff7b72-Tff7b72> Tffa657UnitTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3localNodeNum Tff7b72= Te6edf3nodeManagerTb4b4b4.Te6edf3myNodeNumTb4b4b4.Te6edf3value Tff7b72?: Tff7b72throw Te6edf3LocalNodeUnavailableExceptionTb4b4b4(Ta5d6ff"Ta5d6ffEdit settingsTa5d6ff"Tb4b4b4)
Te6edf3editSettingsTb4b4b4(Te6edf3localNodeNumTb4b4b4, Te6edf3blockTb4b4b4)
Tb4b4b4}

T8b949e/** Binds [AdminEditScope] writes to one destination and stages optimistic projections until commit acceptance. */
Tff7b72private Tff7b72inner Tff7b72class T56d364EditSettingsSessionTb4b4b4(Tff7b72private Tff7b72val Te6edf3destNumTb4b4b4: Tffa657IntTb4b4b4, Tff7b72private Tff7b72val Te6edf3isLocalDestinationTb4b4b4: Tffa657BooleanTb4b4b4) Tb4b4b4:
Te6edf3AdminEditScope Tb4b4b4{
Tff7b72private Tff7b72val Te6edf3projectionLock Tff7b72= Te6edf3SynchronizedObjectTb4b4b4(Tb4b4b4)
Tff7b72private Tff7b72val Te6edf3stagedProjections Tff7b72= Te6edf3mutableListOfTff7b72<Te6edf3suspend Tb4b4b4(Tb4b4b4) Tff7b72-Tff7b72> Tffa657UnitTff7b72>Tb4b4b4(Tb4b4b4)

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffsetOwnerTb4b4b4(Te6edf3userTb4b4b4: Te6edf3UserTb4b4b4) Tb4b4b4{
Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3commandSenderTb4b4b4.Te6edf3generatePacketIdTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{ Te6edf3AdminMessageTb4b4b4(Te6edf3set_owner Tff7b72= Te6edf3userTb4b4b4) Tb4b4b4}
Te6edf3stageProjection Tb4b4b4{ Te6edf3nodeManagerTb4b4b4.Te6edf3handleReceivedUserTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3userTb4b4b4) Tb4b4b4}
Tb4b4b4}

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffsetConfigTb4b4b4(Te6edf3configTb4b4b4: Te6edf3ConfigTb4b4b4) Tb4b4b4{
Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3commandSenderTb4b4b4.Te6edf3generatePacketIdTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{ Te6edf3AdminMessageTb4b4b4(Te6edf3set_config Tff7b72= Te6edf3configTb4b4b4) Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3isLocalDestinationTb4b4b4) Te6edf3stageProjection Tb4b4b4{ Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3setLocalConfigTb4b4b4(Te6edf3configTb4b4b4) Tb4b4b4}
Tb4b4b4}

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffsetModuleConfigTb4b4b4(Te6edf3configTb4b4b4: Te6edf3ModuleConfigTb4b4b4) Tb4b4b4{
Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3commandSenderTb4b4b4.Te6edf3generatePacketIdTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3AdminMessageTb4b4b4(Te6edf3set_module_config Tff7b72= Te6edf3configTb4b4b4)
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3isLocalDestinationTb4b4b4) Tb4b4b4{
Te6edf3stageProjection Tb4b4b4{
Te6edf3configTb4b4b4.Te6edf3statusmessageTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3status Tff7b72-Tff7b72> Te6edf3nodeManagerTb4b4b4.Te6edf3updateNodeStatusTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3statusTb4b4b4.Te6edf3node_statusTb4b4b4) Tb4b4b4}
Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3setLocalModuleConfigTb4b4b4(Te6edf3configTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

T8b949e// Unlike one-shot writes, a transaction can replace several slots. This scope cannot infer the complete target
T8b949e// set, so the operation adding channel writes must reconcile that set after the transaction; mirroring slots
T8b949e// here could expose a partial cache if a later write or commit fails.
Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffsetChannelTb4b4b4(Te6edf3channelTb4b4b4: Te6edf3ChannelTb4b4b4) Tff7b72=
Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3commandSenderTb4b4b4.Te6edf3generatePacketIdTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{ Te6edf3AdminMessageTb4b4b4(Te6edf3set_channel Tff7b72= Te6edf3channelTb4b4b4) Tb4b4b4}

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffsetFixedPositionTb4b4b4(Te6edf3positionTb4b4b4: Te6edf3PositionTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3removesFixedPosition Tff7b72= Te6edf3positionTb4b4b4.Te6edf3isFixedPositionRemovalTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3projectionNodeNum Tff7b72=
Tff7b72if Tb4b4b4(Te6edf3removesFixedPositionTb4b4b4) Tb4b4b4{
Tff7b72null
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3nodeManagerTb4b4b4.Te6edf3myNodeNumTb4b4b4.Te6edf3value Tff7b72?: Tff7b72throw Te6edf3LocalNodeUnavailableExceptionTb4b4b4(Ta5d6ff"Ta5d6ffFixed positionTa5d6ff"Tb4b4b4)
Tb4b4b4}
Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3commandSenderTb4b4b4.Te6edf3generatePacketIdTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3positionTb4b4b4.Te6edf3toFixedPositionAdminMessageTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3projectionNodeNum Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3protoPosition Tff7b72= Te6edf3positionTb4b4b4.Te6edf3toFixedPositionProtoTb4b4b4(Tb4b4b4)
Te6edf3stageProjection Tb4b4b4{
Te6edf3nodeManagerTb4b4b4.Te6edf3handleReceivedPositionTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3projectionNodeNumTb4b4b4, Te6edf3protoPositionTb4b4b4, Te6edf3nowMillisTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72private Tff7b72fun Td2a8ffstageProjectionTb4b4b4(Te6edf3blockTb4b4b4: Te6edf3suspend Tb4b4b4(Tb4b4b4) Tff7b72-Tff7b72> Tffa657UnitTb4b4b4) Tb4b4b4{
Te6edf3synchronizedTb4b4b4(Te6edf3projectionLockTb4b4b4) Tb4b4b4{ Te6edf3stagedProjections Tff7b72+Tff7b72= Te6edf3block Tb4b4b4}
Tb4b4b4}

Tff7b72suspend Tff7b72fun Td2a8ffapplyStagedProjectionsTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3withContextTb4b4b4(Te6edf3NonCancellableTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3projections Tff7b72=
Te6edf3synchronizedTb4b4b4(Te6edf3projectionLockTb4b4b4) Tb4b4b4{ Te6edf3stagedProjectionsTb4b4b4.Te6edf3toListTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3also Tb4b4b4{ Te6edf3stagedProjectionsTb4b4b4.Te6edf3clearTb4b4b4(Tb4b4b4) Tb4b4b4} Tb4b4b4}
Te6edf3projectionsTb4b4b4.Te6edf3forEach Tb4b4b4{ Te6edf3projection Tff7b72-Tff7b72> Te6edf3applyProjectionTb4b4b4(Te6edf3projectionTb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffTooGenericExceptionCaughtTa5d6ff"Tb4b4b4)
Tff7b72private Tff7b72suspend Tff7b72fun Td2a8ffapplyProjectionTb4b4b4(Te6edf3projectionTb4b4b4: Te6edf3suspend Tb4b4b4(Tb4b4b4) Tff7b72-Tff7b72> Tffa657UnitTb4b4b4) Tb4b4b4{
Tff7b72try Tb4b4b4{
Te6edf3projectionTb4b4b4(Tb4b4b4)
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3ExceptionTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3wTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffLocal edit-settings projection failed after device commitTa5d6ff" Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

T8b949e/** Requires the begin boundary to be admitted before any transactional settings writes are issued. */
Tff7b72private Tff7b72suspend Tff7b72fun Td2a8ffrequireBeginBoundaryAcceptedTb4b4b4(Te6edf3destNumTb4b4b4: Tffa657IntTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminAwaitTb4b4b4(Te6edf3destNumTb4b4b4) Tb4b4b4{ Te6edf3AdminMessageTb4b4b4(Te6edf3begin_edit_settings Tff7b72= Tff7b72trueTb4b4b4) Tb4b4b4}Tb4b4b4) Tb4b4b4{
Tff7b72throw Te6edf3EditSettingsTransactionExceptionTb4b4b4(Te6edf3editSettingsBoundaryFailureMessageTb4b4b4(Ta5d6ff"Ta5d6ffbeginTa5d6ff"Tb4b4b4)Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

T8b949e/**
* Applies commit back-pressure. Ordinary writes are already queued FIFO by [CommandSender], so waiting for the
* commit's queue acceptance keeps the caller suspended until the sender has processed every preceding write. This
* prevents a rebooting transport write from overtaking an uncommitted settings transaction.
*/
Tff7b72private Tff7b72suspend Tff7b72fun Td2a8ffrequireCommitBoundaryAcceptedTb4b4b4(Te6edf3destNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3isLocalDestinationTb4b4b4: Tffa657BooleanTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3result Tff7b72= Te6edf3commandSenderTb4b4b4.Te6edf3sendAdminAwaitResultTb4b4b4(Te6edf3destNumTb4b4b4) Tb4b4b4{ Te6edf3AdminMessageTb4b4b4(Te6edf3commit_edit_settings Tff7b72= Tff7b72trueTb4b4b4) Tb4b4b4}
Tff7b72val Te6edf3uncertainAfterDispatch Tff7b72=
Te6edf3isLocalDestination Tff7b72&Tff7b72&
Te6edf3resultTb4b4b4.Te6edf3dispatched Tff7b72&Tff7b72&
Te6edf3resultTb4b4b4.Te6edf3departureEpochAtDispatch Tff7b72!Tff7b72= Tff7b72null Tff7b72&Tff7b72&
Tb4b4b4(Te6edf3resultTb4b4b4.Te6edf3status Tff7b72=Tff7b72= Te6edf3AwaitedSendStatusTb4b4b4.Te6edf3TRANSPORT_STOPPED Tff7b72|Tff7b72| Te6edf3resultTb4b4b4.Te6edf3status Tff7b72=Tff7b72= Te6edf3AwaitedSendStatusTb4b4b4.Te6edf3TIMED_OUTTb4b4b4)
Tff7b72val Te6edf3departedLifecycle Tff7b72=
Tff7b72if Tb4b4b4(Te6edf3uncertainAfterDispatchTb4b4b4) Tb4b4b4{
Te6edf3withTimeoutOrNullTb4b4b4(Te6edf3COMMIT_DEPARTURE_TIMEOUTTb4b4b4) Tb4b4b4{
Te6edf3connectionStateProviderTb4b4b4.Te6edf3connectionLifecycleTb4b4b4.Te6edf3first Tb4b4b4{
Tffa657itTb4b4b4.Te6edf3epochsTb4b4b4.Te6edf3departures Tff7b72> Te6edf3checkNotNullTb4b4b4(Te6edf3resultTb4b4b4.Te6edf3departureEpochAtDispatchTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72null
Tb4b4b4}
T8b949e// A dispatched local commit is durable once a post-dispatch departure is observed. Firmware may move the
T8b949e// connection through Disconnected, Connecting, or DeviceSleep while rebooting.
Tff7b72val Te6edf3committedBeforeLocalDeparture Tff7b72= Te6edf3uncertainAfterDispatch Tff7b72&Tff7b72& Te6edf3departedLifecycle Tff7b72!Tff7b72= Tff7b72null

Tff7b72if Tb4b4b4(Tff7b72!Te6edf3resultTb4b4b4.Te6edf3accepted Tff7b72&Tff7b72& Tff7b72!Te6edf3committedBeforeLocalDepartureTb4b4b4) Tb4b4b4{
Tff7b72throw Te6edf3EditSettingsTransactionExceptionTb4b4b4(Te6edf3editSettingsCommitFailureMessageTb4b4b4(Te6edf3resultTb4b4b4.Te6edf3statusTb4b4b4, Te6edf3resultTb4b4b4.Te6edf3dispatchedTb4b4b4)Tb4b4b4)
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3committedBeforeLocalDepartureTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3i Tb4b4b4{ Ta5d6ff"Ta5d6ffEdit-settings commit dispatched before expected local transport departureTa5d6ff" Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72private Tff7b72companion Tff7b72object Tb4b4b4{
Tff7b72private Tff7b72const Tff7b72val Te6edf3DEFAULT_DELAY_SECONDS Tff7b72= T79c0ff5
Tb4b4b4}
Tb4b4b4}

Served by rngit 1.5.0 - Generated in 0.14s